package game.ouroboros.magic;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import android.util.Log;
import framework.maths.CollisionTester;
import framework.maths.Vector2;
import game.ouroboros.Projectile;
import game.ouroboros.enemy.Enemy;
import game.ouroboros.levels.Level;
import game.ouroboros.traps.Portao;
import game.ouroboros.traps.Trap;

public class World implements PlayerInput {

	public static final float WORLD_WIDTH = 10;
	public static final float WORLD_HEIGHT = 15 * 20;
	public static final int WORLD_STATE_RUNNING = 0;
	public static final int WORLD_STATE_NEXT_LEVEL = 1;
	public static final int WORLD_STATE_GAME_OVER = 2;
	public static final int WORLD_STATE_OVERLOOK = 666;
	public static final int CUSTO = 100;
	public static int mana;
	public final List<Trap> traps;
	public final List<Projectile> projectiles;
	public static List<Vector2> rota0, rota1, rota2;

	private TrapManager trapManager;
	private ModulePersonagem moduleCollision;
	public Level level;
	// public final WorldListener listener;
	public final Random rand;

	public int score;
	public int state;

	public World(int rows, int cols, int sizeX, int sizeY) {
		Log.v("<Chamada>", "World()");
		this.traps = new ArrayList<Trap>(25);
		Log.v("<Chamada>", "World(): Traps");
		this.projectiles = new ArrayList<Projectile>(25);
		Log.v("<Chamada>", "World(): projectiles");
		rand = new Random();
		setTrapManager(new TrapManager(sizeX, sizeY, rows, cols));
		Log.v("<Chamada>", "TrapManager()");
		moduleCollision = new ModulePersonagem(rows, cols, sizeX, sizeY);
		Log.v("<Chamada>", "ModuleCollsion()");
		this.score = 0;
		this.state = WORLD_STATE_RUNNING;
		initRota();
		this.level = new Level(new Vector2(0, 0), trapManager);
	}

	public void generateLevel() {
		initRota();
		this.level.nextLevel();
		
		this.getTrapManager().putTrapInXY(Portao.getPortao(16, 16, 50, 50),
				200, 200);
//		this.traps.addAll(getTrapManager().getObjetivos());

		// this.projectiles.addAll(projectileManager.getProjeteis());
		/**
		 * TODO - > nesse método ocorre a geração dos objetos na tela, o novo
		 * level, ou a troca do mesmo.
		 */
	}

	/**
	 * TODO OK
	 * 
	 * @param deltaTime
	 */
	public void update(float deltaTime) {
		updateTraps(deltaTime);
		updateProjectiles(deltaTime);
		updatePersonagens(deltaTime);
		checkCollisions();
		checkGameOver();
	}

	/**
	 * - OK
	 * 
	 * @param deltaTime
	 */
	private void updateTraps(float deltaTime) {
		int len = traps.size();
		for (int i = 0; i < len; i++) {
			traps.get(i).update(deltaTime);
		}
	}

	private void updateProjectiles(float deltaTime) {
		int len = projectiles.size();
		for (int i = 0; i < len; i++) {
			projectiles.get(i).update(deltaTime);
		}
	}

	private void updatePersonagens(float deltaTime) {
		level.update(deltaTime);
	}

	private void checkCollisions() {
		checkTrapsCollisions();
		checkProjectilesCollisions();
	}

	/**
	 * Funcção que verifica colisões entre o armadilhas e personagens.
	 */
	private void checkTrapsCollisions() {
		this.moduleCollision.clearModuleState();
		this.moduleCollision
				.insertListOfPersonagem(level.getAlivePersonagens());

		int len = traps.size();
		int len2 = -1;
		for (int i = 0; i < len; i++) {
			Trap p = traps.get(i);
			if (!p.funcionando())
				continue;

			List<Enemy> list = this.moduleCollision.grid
					.getPotentialColliders(p);
			len2 = list.size();
			for (int j = 0; j < len2; j++) {
				Enemy enemy = list.get(j);
				if (CollisionTester.collisionRectangles(p.bounds, enemy.bounds)) {
					if (!p.inCollisionRange(enemy)) {
						enemy.collidedWith(p);
					}

				}
			}
		}
	}

	private void checkProjectilesCollisions() {
		this.moduleCollision.clearModuleState();
		this.moduleCollision
				.insertListOfPersonagem(level.getAlivePersonagens());

		int len = projectiles.size();
		int len2 = -1;
		for (int i = 0; i < len; i++) {
			Projectile p = projectiles.get(i);
			if (!p.isAlive())
				continue;

			List<Enemy> list = this.moduleCollision.grid
					.getPotentialColliders(p);
			len2 = list.size();
			for (int j = 0; j < len2; j++) {
				Enemy enemy = list.get(j);
				if (CollisionTester.collisionRectangles(p.bounds, enemy.bounds)) {
					if (!p.inCollisionRange(enemy)) {
						enemy.collidedWith(p);
					}

				}
			}
		}
	}

	private void checkGameOver() {
		List<Trap> p = getTrapManager().getObjetivos();
		if (p.isEmpty()) {
			this.state = WORLD_STATE_GAME_OVER;
		}

	}

	@Override
	public boolean putObjectInXY(Trap p, float x, float y) {
		if (getTrapManager().putTrapInXY(p, x, y)) {
			traps.add(p);
			return true;
		}
		return false;
	}

	public void initRota() {
		// campo de 800x800
		World.rota0 = new ArrayList<Vector2>(7);
		World.rota1 = new ArrayList<Vector2>(3);
		World.rota2 = new ArrayList<Vector2>(6);

		World.rota0.add(new Vector2(208, 784)); // spawn
		World.rota0.add(new Vector2(208, 300));
		World.rota0.add(new Vector2(16, 300));
		World.rota0.add(new Vector2(16, 100));
		World.rota0.add(new Vector2(436, 100));
		World.rota0.add(new Vector2(436, 16));
		World.rota0.add(new Vector2(16, 16)); // portao

		World.rota1.add(new Vector2(436, 784)); // spawn
		World.rota1.add(new Vector2(436, 16));
		World.rota1.add(new Vector2(16, 16)); // portao

		World.rota2.add(new Vector2(646, 784)); // spawn
		World.rota2.add(new Vector2(646, 200));
		World.rota2.add(new Vector2(784, 50));
		World.rota2.add(new Vector2(436, 50));
		World.rota2.add(new Vector2(436, 16));
		World.rota2.add(new Vector2(16, 16)); // portao
	}

	public TrapManager getTrapManager() {
		return trapManager;
	}

	public void setTrapManager(TrapManager trapManager) {
		this.trapManager = trapManager;
	}
}
